
#include <cuda_runtime_api.h>
#define __host__
#define __device__
#include <vector_types.h>

#include <algorithm/analytical_model/algorithm/cuda/grid/Grid.cuh>
#include <algorithm/analytical_model/algorithm/cuda/grid/RectangleGrid.cuh>
#include <algorithm/analytical_model/algorithm/cuda/heliostat/RectangleHeliostat.cuh>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/grid/Grid.h>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/grid/RectangleGrid.h>
#include <algorithm/analytical_model/algorithm/cuda/inter_op/heliostat/RectangleHeliostat.h>
#include <algorithm/analytical_model/algorithm/cuda/Utils.h>
#include <utils/Print.h>
#include <utils/Utils.h>
#include <utils/config.h>
#include <utils/Format.h>

#include <iostream>
#include <memory>

using namespace solar::cuda::inter_op;

RectangleGrid::RectangleGrid()
{
    this->delegate_ptr_ = std::make_shared<solar::cuda::RectangleGrid>();
}

auto RectangleGrid::gridHelioMatch(const std::vector<RectangleHeliostat>& heliostats) const -> int
{
    throw "disabled for now";
    // std::vector<solar::cuda::RectangleHeliostat*> vec;
    // vec.resize(heliostats.size(), nullptr);
    // SOLAR_OMP_PARALLEL_FOR_SIMD
    // for (auto i = 0; i < heliostats.size(); i++)
    // {
    //     vec[i] = heliostats[i].delegate_ptr_.get();
    // }
    // return this->delegate_ptr_->gridHelioMatch(vec);
}

auto RectangleGrid::gridHelioMatchGPU(const std::vector<RectangleHeliostat>& heliostats) const
    -> void
{
    std::vector<solar::cuda::RectangleHeliostat> h_heliostats(heliostats.size());
    SOLAR_OMP_PARALLEL_FOR_SIMD
    for (auto i = 0; i < heliostats.size(); i++)
    {
        h_heliostats[i] = *heliostats[i].delegate_ptr_;
    }
    solar::cuda::RectangleHeliostat* d_heliostats = nullptr;
    auto ptr = std::dynamic_pointer_cast<solar::cuda::RectangleGrid>(this->delegate_ptr_);
    cpu2gpuAsync(d_heliostats, h_heliostats.data(), heliostats.size(), ptr->stream_);
    ptr->gridHelioMatch(d_heliostats);
    cudaFreeAsync(d_heliostats, ptr->stream_);
}

void RectangleGrid::init() const { this->delegate_ptr_->init(); }

void RectangleGrid::clear() const { this->delegate_ptr_->clear(); }

auto RectangleGrid::getSubGridNum() const -> Int3
{
    auto ptr = std::dynamic_pointer_cast<solar::cuda::RectangleGrid>(this->delegate_ptr_);
    return structCopy<Int3>(ptr->subgrid_num_);
}

auto RectangleGrid::getNumGridHelioMatch() const -> std::size_t
{
    auto ptr = std::dynamic_pointer_cast<solar::cuda::RectangleGrid>(this->delegate_ptr_);
    return ptr->num_grid_helio_match_;
}

auto RectangleGrid::getCudaStream() const -> cudaStream_t
{
    auto ptr = std::dynamic_pointer_cast<solar::cuda::RectangleGrid>(this->delegate_ptr_);
    return ptr->stream_;
}
